package com.tiennt.android.droidcamreader.camera;

import java.io.IOException;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

import android.graphics.Point;
import android.graphics.Rect;
import android.hardware.Camera;
import android.hardware.Camera.AutoFocusCallback;
import android.hardware.Camera.PictureCallback;
import android.hardware.Camera.ShutterCallback;
import android.hardware.Camera.Size;
import android.view.SurfaceHolder;

import com.tiennt.android.droidcamreader.CameraActivity;
import com.tiennt.android.droidcamreader.PlanarYUVLuminanceSource;

public class CameraManager {

	public Camera mCamera;
	public CameraActivity mCamActivity;

	private Point mScreenDimension;
	private Point mPreviewSize;

	public CameraManager(CameraActivity context) {
		mCamActivity = context;
		mScreenDimension = mCamActivity.getScreenDimension();
	}

	public synchronized void openCamera() throws Exception {
		if (mCamera == null) {
			mCamera = Camera.open();
			if (mCamera == null) {
				throw new Exception("Cannot open camera.");
			}
			initCameraConfig();
		}

	}

	public void closeCamera() {
		if (mCamera != null) {
			mCamera.release();
			mCamera = null;
		}
	}

	public void setCameraPreview(SurfaceHolder holder) throws IOException {
		mCamera.setPreviewDisplay(holder);
	}

	public void takePicture(final ShutterCallback shutterCallback,
			final PictureCallback JpegCallback) {
		mCamera.autoFocus(new Camera.AutoFocusCallback() {
			public void onAutoFocus(boolean success, Camera camera) {
				camera.takePicture(shutterCallback, null, JpegCallback);
			}
		});
	}

	public void camFocus(AutoFocusCallback autoFocusCallback) {
		mCamera.autoFocus(autoFocusCallback);
	}

	public synchronized void startPreview() {
		if (mCamera != null) {
			mCamera.startPreview();
		}
	}

	public synchronized void stopPreview() {
		if (mCamera != null) {
			mCamera.stopPreview();
		}
	}

	public Point findBestPicturePreviewSize() {
		Camera.Parameters parameters = mCamera.getParameters();
		List<Size> sizes = parameters.getSupportedPreviewSizes();

		Collections.sort(sizes, new Comparator<Size>() {

			@Override
			public int compare(Size lhs, Size rhs) {
				// TODO Auto-generated method stub
				int lPixels = lhs.width * lhs.height;
				int rPixels = rhs.width * rhs.height;
				if (lPixels < rPixels)
					return -1;
				else if (lPixels > rPixels)
					return 1;
				return 0;
			}
		});

		float diff = Float.POSITIVE_INFINITY;
		float screenAspectRatio = (float) mScreenDimension.x
				/ mScreenDimension.y;
		Point bestSize = null;
		for (Size size : sizes) {
			if (size.width == mScreenDimension.x
					&& size.height == mScreenDimension.y) {
				bestSize = new Point(size.width, size.height);
				return bestSize;
			}
			float aspectRatio = (float) size.height / size.width;
			float newDiff = Math.abs(aspectRatio - screenAspectRatio);
			if (newDiff < diff) {
				bestSize = new Point(size.width, size.height);
				diff = newDiff;
			}
		}
		return bestSize;
	}

	public void initCameraConfig() {
		Camera.Parameters params = mCamera.getParameters();

		mPreviewSize = findBestPicturePreviewSize();
		params.setPreviewSize(mPreviewSize.x, mPreviewSize.y);

		mCamera.setParameters(params);
	}

	public Rect getCropRectInPreviewPicture() {
		Rect cropRectInScreen = mCamActivity.getCropView().getCropRectangle();

		float ratioX = (float) mPreviewSize.x / mScreenDimension.x;
		float ratioY = (float) mPreviewSize.y / mScreenDimension.y;

		int left = (int) (cropRectInScreen.left * ratioX);
		int right = (int) (cropRectInScreen.right * ratioX);
		int top = (int) (cropRectInScreen.top * ratioY);
		int bottom = (int) (cropRectInScreen.bottom * ratioY);

		return new Rect(left, top, right, bottom);
	}

	public PlanarYUVLuminanceSource buildLuminanceSource(byte[] data,
			int width, int height) {
		Rect rect = getCropRectInPreviewPicture();
		if (rect == null) {
			return null;
		}
		// Go ahead and assume it's YUV rather than die.
		return new PlanarYUVLuminanceSource(data, width, height, rect.left,
				rect.top, rect.width(), rect.height(), false);
	}

	public Point getPreviewSize() {
		return mPreviewSize;
	}

	public Camera getCamera() {
		return mCamera;
	}

	public void turnOnTorch() {
		Camera.Parameters params = mCamera.getParameters();
		params.setFlashMode(Camera.Parameters.FLASH_MODE_ON);
		mCamera.setParameters(params);

		// mCamera.setOneShotPreviewCallback(new Camera.PreviewCallback() {
		//
		// @Override
		// public void onPreviewFrame(byte[] data, Camera camera) {
		// // TODO Auto-generated method stub
		// Camera.Parameters params = mCamera.getParameters();
		// params.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);
		// mCamera.setParameters(params);
		// }
		// });
	}

	public void turnOffTorch() {
		Camera.Parameters params = mCamera.getParameters();
		params.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);
		mCamera.setParameters(params);

	}
}
